package com.mitou.base.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mitou.base.entity.BaseRole;
import com.mitou.base.entity.BaseUser;
import com.mitou.base.entity.BaseUserRole;
import com.mitou.base.entity.dto.BaseUserLoginDto;
import com.mitou.base.entity.dto.BaseUserSaveDto;
import com.mitou.base.entity.dto.BaseUserUpdatePwdDto;
import com.mitou.base.entity.query.BaseMenuHasQuery;
import com.mitou.base.entity.query.BaseUserQuery;
import com.mitou.base.entity.vo.BaseMenuVo;
import com.mitou.base.entity.vo.BaseUserLoginVo;
import com.mitou.base.entity.vo.BaseUserVo;
import com.mitou.base.mapper.BaseUserMapper;
import com.mitou.base.service.IBaseMenuService;
import com.mitou.base.service.IBaseRoleService;
import com.mitou.base.service.IBaseUserRoleService;
import com.mitou.base.service.IBaseUserService;
import com.mitou.common.constants.BaseConstants;
import com.mitou.common.response.Result;
import com.mitou.common.response.ResultCode;
import com.mitou.common.utils.SecretKeyUtil;
import com.mitou.common.utils.web.BaseContextUtil;
import com.mitou.common.utils.web.RedisCacheUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author rice
 * @since 2021-03-25
 */
@Service
public class BaseUserServiceImpl extends ServiceImpl<BaseUserMapper, BaseUser> implements IBaseUserService {

    @Resource
    private BaseUserMapper baseUserMapper;
    @Resource
    private BaseContextUtil baseContextUtil;
    @Resource
    private IBaseUserRoleService baseUserRoleService;
    @Resource
    private IBaseRoleService baseRoleService;
    @Resource
    private IBaseMenuService baseMenuService;
    @Resource
    private RedisCacheUtil redisCacheUtil;

    @Override
    public BaseUserVo getById(Long userId) {
        BaseUserVo baseUserVo = null;
        BaseUser baseUser = super.getById(userId);
        if (null != baseUser) {
            baseUserVo = new BaseUserVo();
            BeanUtils.copyProperties(baseUser, baseUserVo);
            List<BaseRole> roleList = baseRoleService.getByUserId(baseUserVo.getUserId());
            baseUserVo.setRoleList(roleList);
        }
        return baseUserVo;
    }

    @Override
    public IPage<BaseUser> page(BaseUserQuery query) {
        LambdaQueryWrapper<BaseUser> lqw = new LambdaQueryWrapper<>();
        //进行条件组装
        //默认查询未删除的用户
        if (null == query.getDelFlag()) {
            query.setDelFlag(BaseConstants.DEL_FALSE);
        }
        lqw.eq(BaseUser::getDelFlag, query.getDelFlag());
        if (StringUtils.isNotBlank(query.getUserName())) {
            lqw.like(BaseUser::getUserName, query.getUserName());
        }
        if (null != query.getPhone()) {
            lqw.like(BaseUser::getPhone, query.getPhone());
        }
        //分页对象
        return super.page(query.page(), lqw);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean register(BaseUserSaveDto saveDto) {
        BaseUser baseUser = new BaseUser();
        BeanUtils.copyProperties(saveDto, baseUser);
        return this.register(baseUser, false);
    }

    @Override
    public boolean checkLoginNameLegal(String loginName) {
        BaseUser one = super.getOne(
                new LambdaQueryWrapper<BaseUser>()
                        .select(BaseUser::getLoginName)
                        .eq(BaseUser::getLoginName, loginName)
        );
        return null == one;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteByIds(List<Long> userIds) {
        //清除掉与此用户的角色关联
        baseUserRoleService.remove(new LambdaQueryWrapper<BaseUserRole>().in(BaseUserRole::getUserId, userIds));
        return super.removeByIds(userIds);
    }

    @Override
    public Result<BaseUserLoginVo> login(BaseUserLoginDto baseUserLoginDto) {
        LambdaQueryWrapper<BaseUser> lqw = new LambdaQueryWrapper<>();
        lqw.eq(BaseUser::getLoginName, baseUserLoginDto.getLoginName());
        BaseUser one = super.getOne(lqw);
        if (null == one) {
            return Result.fail(ResultCode.USER_LOGIN_ERROR);
        }
        if (!SecretKeyUtil.priDecrypt(one.getUserPwd()).equals(baseUserLoginDto.getUserPwd())) {
            return Result.fail(ResultCode.USER_PWD_ERROR);
        }
        return Result.success(this.handleSuccessLogin(one));
    }

    @Override
    public boolean logout() {
        return baseContextUtil.removeToken();
    }

    @Override
    public Result<Boolean> updatePwd(BaseUserUpdatePwdDto updatePwdDto) {
        Long userId = null == updatePwdDto.getUserId() ? baseContextUtil.getUserId() : updatePwdDto.getUserId();
        BaseUser byId = super.getById(userId);
        if (null == byId) {
            return Result.fail(ResultCode.USER_LOGIN_ERROR);
        }
        String userPwd = SecretKeyUtil.priDecrypt(byId.getUserPwd());
        if (!userPwd.equals(updatePwdDto.getOldUserPwd())) {
            return Result.fail(ResultCode.USER_PWD_ERROR);
        }
        userPwd = SecretKeyUtil.pubEncrypt(updatePwdDto.getUserPwd());
        BaseUser baseUser = new BaseUser();
        baseUser.setUserId(userId);
        baseUser.setUserPwd(userPwd);
        return Result.success(super.updateById(baseUser));
    }

    /**
     * 用户表注册，做用户注册时的一些初始化操作
     *
     * @param baseUser            用户信息
     * @param autoGiveDefaultRole 是否赋予默认角色
     * @return
     */
    private boolean register(BaseUser baseUser, boolean autoGiveDefaultRole) {
        baseUser.setCreateTime(new Date());
        String userPwd = baseUser.getUserPwd();
        if (StringUtils.isBlank(userPwd)) {
            userPwd = BaseConstants.DEFAULT_PWD;
        }
        //密码加密
        baseUser.setUserPwd(SecretKeyUtil.pubEncrypt(userPwd));
        boolean save = super.save(baseUser);
        if (save) {
            if (autoGiveDefaultRole) {
                BaseRole baseRole = baseRoleService.getDefaultRole();
                if (null != baseRole) {
                    BaseUserRole baseUserRole = new BaseUserRole();
                    baseUserRole.setUserId(baseUser.getUserId());
                    baseUserRole.setRoleId(baseRole.getRoleId());
                    save = baseUserRoleService.save(baseUserRole);
                }
            }
        }
        return save;
    }

    /**
     * 当登录校验通过后，在此做返回前的处理。
     * 如：清除用户信息中包含的隐秘字段、记录登录时间、缓存用户信息 等等
     *
     * @param baseUser 用户信息
     * @return
     */
    private BaseUserLoginVo handleSuccessLogin(BaseUser baseUser) {
        //1.只返回页面所需部分信息
        BaseUserLoginVo baseUserLoginVo = new BaseUserLoginVo();
        BeanUtils.copyProperties(baseUser, baseUserLoginVo);
        //2.生成token返回
        String token = baseContextUtil.generateToken(baseUser);
        baseUserLoginVo.setToken(token);
        //3.获取该用户的权限信息集合，赋给用户信息，之后鉴权使用
        List<BaseMenuVo> menuList = baseMenuService.selectHas(new BaseMenuHasQuery().setUserId(baseUser.getUserId()));
        if (!menuList.isEmpty()) {
            baseUser.setPermissionSet(
                    menuList.stream().map(BaseMenuVo::getMenuCode).collect(Collectors.toSet())
            );
        }
        //4.把用户信息放入redis
        redisCacheUtil.setStr(token, JSON.toJSONString(baseUser), BaseConstants.TOKEN_DURATION_TIME, TimeUnit.HOURS);
        return baseUserLoginVo;
    }

}
